package ru.btabank.dom.xpath.expression;

import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import ru.btabank.dom.util.DOMUtil;
import ru.btabank.dom.xpath.XPathException;

public class ChildStep extends NameStep {
    private Integer predicate;

    private boolean hasPredicate;

    public ChildStep(String prefix, String localName, String namespaceURI, Integer predicate) {
        super(prefix, localName, namespaceURI);
        this.predicate = predicate;
        this.hasPredicate = this.predicate != null;
    }

    protected int getPredicate() {
        return this.predicate.intValue();
    }

    protected boolean hasPredicate() {
        return this.hasPredicate;
    }

    public NodeSet select(NodeSet source) {
        NodeSet temp, target;
        Node sourceNode, childNode;
        NodeList childNodes;

        target = new NodeSet();
        temp = new NodeSet();
        for (int sourceIndex = 0; sourceIndex < source.getLength(); sourceIndex++) {
            sourceNode = source.item(sourceIndex);
            childNodes = sourceNode.getChildNodes();
            for (int childIndex = 0; childIndex < childNodes.getLength(); childIndex++) {
                childNode = childNodes.item(childIndex);
                if (childNode.getNodeType() == Node.ELEMENT_NODE && super.matches(childNode)) {
                    temp.add(childNode);
                }
            }
            if (this.hasPredicate() && temp.getLength() > 0) {
                if (this.getPredicate() == 0)
                    temp = new NodeSet();
                else if (this.getPredicate() > temp.getLength())
                    temp = new NodeSet();
                else
                    temp = new NodeSet(temp.item(this.getPredicate() - 1));
            }
            target.add(temp);
            temp.clear();
        }
        return target;
    }

    public NodeSet build(NodeSet source) throws XPathException {
        NodeSet temp, target;
        Node sourceNode, childNode;
        NodeList childNodes;

        target = new NodeSet();
        temp = new NodeSet();

        for (int sourceIndex = 0; sourceIndex < source.getLength(); sourceIndex++) {
            sourceNode = source.item(sourceIndex);
            childNodes = sourceNode.getChildNodes();
            for (int childIndex = 0; childIndex < childNodes.getLength(); childIndex++) {
                childNode = childNodes.item(childIndex);
                if (childNode.getNodeType() == Node.ELEMENT_NODE && super.matches(childNode)) {
                    temp.add(childNode);
                }
            }
            if (this.hasPredicate()) {
                if (this.getPredicate() == 0)
                    temp = new NodeSet();
                else {
                    for (; temp.getLength() < this.getPredicate();) {
                        childNode = DOMUtil.createElement(sourceNode, super.getName(), super
                            .getNamespaceURI());
                        temp.add(childNode);
                    }
                    temp = new NodeSet(temp.item(this.getPredicate() - 1));
                }
            } else {
                if (temp.getLength() == 0) {
                    childNode = DOMUtil.createElement(sourceNode, super.getName(), super.getNamespaceURI());
                    temp.add(childNode);
                }
            }
            target.add(temp);
            temp.clear();
        }
        return target;
    }

    public String toString() {
        if (this.hasPredicate)
            return super.getName() + "[" + this.predicate + "]";
        else
            return super.getName();
    }
}
